package engine;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.logging.Level;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import enemies.DumbNinja;
import enemies.Enemy;






public class Game extends JPanel implements Runnable, KeyListener {
	private final int WIDTH=720;
	private final int HEIGHT=1280;
	private final double SCALE=0.5;
	private double gameSpeed = 4;
	private Ninja ninja;
	private Image image;
	private Graphics graphics;
	private BufferStrategy strategy;
	private BufferedImage background;
	private Game game;
	private Graphics2D g2d;
	private static Background bg1, bg2;
	public enum GameState{STARTING, INITIATING, GAME_CONTENT_LOADING, MAIN_MENU, OPTIONS, PLAYING, GAMEOVER, DESTROYED}
	private GameState gameState;
	private int platformsRate = 200, enemiesRate = 400;
	private ArrayList<Platform> platforms = new ArrayList<Platform>();
	private ArrayList<Enemy> enemies = new ArrayList<Enemy>();
	private double platformsUpdateRate = 0.5; //miliseconds      60 = 1 second
	private int framesPassed = 0;
	
	public Game(){
		super();
		setFocusable(true);
		addKeyListener(this);
	}
	
	@Override
    public void run(){
		
		double nsPerTick = 1000000000.0 / 60;
		long startTime = System.nanoTime();
		long lastTime = System.nanoTime();
		long lastTimeFramed = System.nanoTime(); //update das plataformas
		boolean platformsUpdate=false;
		while(true){
			
			long now = System.nanoTime();
			if(((now - lastTimeFramed) / nsPerTick) > 60){
				lastTimeFramed=now;
				System.out.println("FPS = " + framesPassed);
				framesPassed=0;
			}
			
			try {
				Thread.sleep(2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			if(((now - lastTime) / nsPerTick) > 1){
				bg1.update();
				bg2.update();
				lastTime=now;
				/**
				 *  Update das plataformas
				 */
				if(platforms.size()==0 || platforms.get(platforms.size()-1).getY()>platformsRate){
					Platform platform = new Platform(this);
					addPlatform(platform);
					if (enemies.size() == 0 || enemies.get(enemies.size()-1).getY()>enemiesRate)
						addEnemy(new DumbNinja(platform.getX()+ platform.getxLength()/2, this));
				}
				if(platforms.get(0).getY()> getHeight()+100)
					platforms.remove(0);

				for(Platform p : platforms){
					p.update();
				}
				
				/**
				 *  Update dos inimigos
				 */
				ArrayList<Enemy> aux = new ArrayList<Enemy>(enemies);
				for (Enemy e : aux){
					e.update();
					if (e.getY() >= getHeight() || !e.isAlive()){
						enemies.remove(e);
					}
				}
				ninja.update();
			}
			repaint();
			
			
			
		}
        
    }
	  
	
	
	




	@Override
	public void paintComponent( Graphics g ){
		/*if (image == null) {
			image = createImage(this.getWidth(), this.getHeight());
			graphics = image.getGraphics();
		}
		graphics.setColor(getBackground());
		graphics.fillRect(0, 0, getWidth(), getHeight());
		graphics.setColor(getForeground());
		paint(graphics); 
		g.drawImage(image, 0, 0, this);
		graphics.dispose();
		g.dispose();*/
		
		/*
		paint(g);
		g.dispose();
		*/
		
		/*
		super.paintComponent(g);
		g2d = (Graphics2D)g; 
		super.paintComponent(g2d);
		g.setColor(Color.white);
		switch (gameState) {
		case PLAYING:
			g2d.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
			g2d.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
			break;

		default:
			break;
		}*/
		
    }
	
	public void paint(Graphics g){
		framesPassed++;
		switch (gameState) {
		case PLAYING:
			g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
			g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
			for(Platform p : platforms)
				g.drawImage(p.getImage(), p.getX(), p.getY(), p.getxLength(), p.getyLength(), null);
			
			g.setColor(Color.GREEN);
			for (Enemy e : enemies){
				g.fillRect(e.getX(), e.getY() - 5, (int) e.getVit(), 3);
				g.drawImage(e.getImage(), e.getX(), e.getY(),null);
			}
			g.fillRect(ninja.getX(), ninja.getY()-5, (int)ninja.getVit(), 3);
			g.drawImage(ninja.getImage(), ninja.getX(), ninja.getY(), ninja.getWIDTH(), ninja.getHEIGHT(), null);
			if (ninja.isSwordAttacking())
				g.drawImage(ninja.getSwordEffects(), ninja.getX()-ninja.getWIDTH(), ninja.getY(),ninja.getWIDTH()*3, ninja.getHEIGHT(), null);
			break;

		default:
			break;
		}
	}
	
	
	
	

	
	 
	public void start(){
		bg1 = new Background(0, 0,this);
		bg2 = new Background(0, -getHeight(),this);
		ninja = new Ninja(this);
		gameState = GameState.PLAYING;
		 //We start game in new thread.
		Thread thread = new Thread(this);
		thread.start();
	}
	
	
	public void init(){
		gameState=GameState.INITIATING;
		loadContent();
	}

	private void loadContent(){
        try{
            URL backgroundURL = this.getClass().getResource("/data/stone_wall.png");
            background = ImageIO.read(backgroundURL);
            background = resize(background, getWidth(), getHeight());
           // grph.scale(1, 1);
           // grph.dispose();
        }
        catch (IOException ex) {
        	
        }
    }
	
	public BufferedImage resize(BufferedImage img, int newW, int newH) { 
	    Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
	    BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);

	    Graphics2D g2d = dimg.createGraphics();
	    g2d.drawImage(tmp, 0, 0, null);
	    g2d.dispose();

	    return dimg;
	}
	public static void main(String [] args){
		
		Game game = new Game();
		
		JFrame frame = new JFrame();
		frame.setSize(game.getWidth()+16, game.getHeight()+38);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLayout(new BorderLayout());
		frame.add(game);
		frame.setVisible(true);
		game.init();
		game.start();
		
	}

	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			ninja.jump();
			break;
		case KeyEvent.VK_LEFT:
			ninja.moveLeft();
			break;

		case KeyEvent.VK_RIGHT:
			ninja.moveRight();
			break;

		case KeyEvent.VK_DOWN:
			new Platform(this);
			break;
		case KeyEvent.VK_SPACE:
			ninja.swordAttack();
			break;
		}
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {

		case KeyEvent.VK_LEFT:
			ninja.stopLeft();
			break;

		case KeyEvent.VK_RIGHT:
			ninja.stopRight();
			break;
		}
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public int getWidth() {
		return (int)(WIDTH*SCALE);
	}

	public int getHeight() {
		return (int)(HEIGHT*SCALE);
	}

	public double getScale() {
		return SCALE;
	}

	public double getGameSpeed() {
		return gameSpeed;
	}
	
	public void addPlatform(Platform platform) {
		platforms.add(platform);
	}

	public ArrayList<Platform> getPlatforms() {
		return platforms;
	}

	public BufferedImage createImage(String url){
		BufferedImage i = null;
		URL URL = this.getClass().getResource(url);
		try {i = ImageIO.read(URL);} catch (IOException e) {e.printStackTrace();}
		return i;
	}
	
	public void addEnemy(Enemy e){
		enemies.add(e);
	}

	public ArrayList<Enemy> getEnemies() {
		return enemies;
	}
}
